<?php

namespace common\service;

use common\model\EntityModel;
use common\model\StepCategoryAttributeModel;
use common\model\StepModel;
use common\model\StepSkuModel;
use common\model\StepWorkflowModel;
use common\model\TaskModel;
use support\ErrorCode;
use support\SingletonTrait;

class StepSkuService
{

    // 单例工具
    use SingletonTrait;

    /**
     * 查询工序任务工时
     * @param $entitySkuVal
     * @param $stepCategoryData
     * @return array
     */
    public function getTaskStepSkuCategoryManHour($entitySkuVal, $stepCategoryData)
    {
        $entitySkuStrMd5s = [];
        $afterSkuStr = join(':', $entitySkuVal);

        foreach ($stepCategoryData as $stepCategoryItem) {
            APP_DEBUG && trace(var_export("{$stepCategoryItem['name']}:{$afterSkuStr}", true), "DEBUG");
            $entitySkuStrMd5s[] = md5("{$stepCategoryItem['name']}:{$afterSkuStr}");
        }

        $stepSkuModelModel = model(StepSkuModel::class);
        $attributeManHours = $stepSkuModelModel->field('id,man_hour')->where(['attribute_value_md5' => ['IN', join(',', $entitySkuStrMd5s)]])->select();
        APP_DEBUG && trace(var_export($entitySkuStrMd5s, true), "DEBUG");
        APP_DEBUG && trace(var_export($attributeManHours, true), "DEBUG");
        $manHour = 0;
        foreach ($attributeManHours as $attributeManHour) {
            $manHour += (float)$attributeManHour['man_hour'];
        }
        $skuId = array_column($attributeManHours, "id");

        return [$manHour, $skuId];
    }

    /**
     * 获取任务工序分类SKU规则映射, 通过已知实体数据
     * @param $entityAttrData
     * @param $stepCategoryData
     * @param $attributeRule
     * @return array
     */
    public function getTaskStepSkuCategoryMappingByData($entityAttrData, $stepCategoryData, $attributeRule)
    {
        $entitySkuVal = EntityService::getInstance()->getEntitySkuValuesByData($entityAttrData, $attributeRule);
        return $this->getTaskStepSkuCategoryManHour($entitySkuVal, $stepCategoryData);
    }

    /**
     * 生成实体工序分类的预估工时
     * @param $entityAttrData
     * @param $entityModuleId
     * @param $linkId
     * @param string $stepWorkflowId
     * @return float|int
     */
    public function getEntityStepCategoryManHoursByAttrParam($entityAttrData, $entityModuleId, $linkId, $stepWorkflowId = 0)
    {
        $fieldService = FieldService::getInstance();
        $attributeRule = $fieldService->getEntityAttributeCustomFieldsMapping($entityModuleId);

        if (empty($stepWorkflowId)) {
            throw_strack_exception("can`t found task workflow config", ErrorCode::TASK_WORKFLOW_CONFIG_NOT_EXIST);
        }
        $stepWorkflowModel = model(StepWorkflowModel::class);
        $workFlow = $stepWorkflowModel->where(['id' => $stepWorkflowId])->field('JSON_UNQUOTE(JSON_EXTRACT(config,"$.nodes")) as nodes')->find();
        $workFlowNodes = json_decode($workFlow['nodes'], true);
        $stepIds = [];
        foreach ($workFlowNodes as $node) {
            $stepIds[] = $node[0]['id'];
        }
        $stepModel = model(StepModel::class);
        $stepData = $stepModel->where(['id' => ['IN', join(',', $stepIds)], 'step_category_id' => $linkId])->field('id,name')->select();

        // step_category 工序分类类型，多条sku累加得到工时
        list($taskManHour,) = $this->getTaskStepSkuCategoryMappingByData($entityAttrData, $stepData, $attributeRule);

        return $taskManHour;
    }

    /**
     * 获取任务工序分类SKU规则映射
     * @param $entityId
     * @param $stepCategoryData
     * @param $attributeRule
     * @return array
     */
    public function getTaskStepSkuCategoryMapping($entityId, $stepCategoryData, $attributeRule)
    {
        $entityService = EntityService::getInstance();
        $entitySkuVal = $entityService->getEntitySkuValues($entityId, $attributeRule);
        return $this->getTaskStepSkuCategoryManHour($entitySkuVal, $stepCategoryData);
    }

    /**
     * 自动计算任务工时
     * @param $entityId
     * @param $entityModuleId
     * @param $stepType
     * @param $linkId
     * @param string $stepWorkflowId
     * @return array
     */
    public function autoCalculationManHourByEntity($entityId, $entityModuleId, $stepType, $linkId, $stepWorkflowId = 0)
    {
        $fieldService = FieldService::getInstance();
        $attributeRule = $fieldService->getEntityAttributeCustomFieldsMapping($entityModuleId);

        $moduleAttributeList = model(StepCategoryAttributeModel::class)
            ->join("attribute ON attribute.id = step_category_attribute.attribute_id")
            ->join('step_category on step_category.id = step_category_attribute.step_category_id')
            ->where(['step_category.entity_id' => $entityModuleId])
            ->field("attribute.*")
            ->select();
        APP_DEBUG && trace(implode(',', array_column($moduleAttributeList, 'name')), 'DEBUG');
        $moduleAttributeList = array_column($moduleAttributeList, 'id');
        $attributeRule = array_filter($attributeRule, function ($i) use ($moduleAttributeList) {
            return in_array($i['attribute_id'], $moduleAttributeList);
        });
        $attributeRule = array_values($attributeRule);
        APP_DEBUG && trace(implode(',', array_column($attributeRule, 'field')), 'DEBUG');
        $stepService = StepService::getInstance();
        $entityService = EntityService::getInstance();
        $stepSkuIds = [];
        $taskManHour = 0;
        switch ($stepType) {
            case 'step':
                // step 工序类型，根据所属实体属性匹配一条SKU得到工时
                list($taskManHour, $stepSkuIds[0]) = $entityService->getTaskStepManHour($entityId, $stepService->getStep($linkId), $attributeRule);
                break;
            case 'step_category':
                $stepData = StepWorkflowService::getInstance()->getWorkFlowStepCategoryStepList($stepWorkflowId, $linkId);
                if (!empty($stepData)) {
                    // step_category 工序分类类型，多条sku累加得到工时
                    list($taskManHour, $stepSkuIds) = $this->getTaskStepSkuCategoryMapping($entityId, $stepData, $attributeRule);
                }
                break;
            default:
        }

        return [$taskManHour, $stepSkuIds];
    }

    /**
     * 自动计算任务工时
     * @param array $taskIds
     * @return array
     */
    public function autoCalculationManHourByTask($taskIds = [])
    {
        /**
         * 判断当前任务类型
         * 1、step 工序类型，根据所属实体属性匹配一条SKU得到工时
         * 2、step_category 工序分类类型，多条sku累加得到工时
         */
        $taskManHour = [];
        if (!empty($taskIds)) {
            $taskData = model(TaskModel::class)->field('id,man_hour,step_type,step_category_id,step_id,entity_id,entity_module_id')
                ->where(['id' => ['IN', join(',', $taskIds)]])
                ->select();

            $entityModuleIds = [];
            $entityModuleAttributeCustomFieldsMapping = [];

            $fieldService = FieldService::getInstance();
            $stepService = StepService::getInstance();
            $entityService = EntityService::getInstance();
            foreach ($taskData as $taskItem) {
                if (!in_array($taskItem['entity_module_id'], $entityModuleIds)) {
                    $entityModuleIds[] = $taskItem['entity_module_id'];
                }

                if (!array_key_exists($taskItem['entity_module_id'], $entityModuleAttributeCustomFieldsMapping)) {
                    $entityModuleAttributeCustomFieldsMapping[$taskItem['entity_module_id']] = $fieldService->getEntityAttributeCustomFieldsMapping($taskItem['entity_module_id']);
                }

                if (!empty($taskItem['man_hour'])) {
                    switch ($taskItem['step_type']) {
                        case 'step':
                            // step 工序类型，根据所属实体属性匹配一条SKU得到工时
                            list($manHour,) = $entityService->getTaskStepManHour($taskItem['entity_id'], $stepService->getStep($taskItem['step_id']), $entityModuleAttributeCustomFieldsMapping[$taskItem['entity_module_id']]);
                            $taskManHour[$taskItem['id']] = $manHour;
                            break;
                        case 'step_category':
                            // step_category 工序分类类型，多条sku累加得到工时
                            list($manHour,) = $this->getTaskStepSkuCategoryMapping($taskItem['entity_id'], $stepService->getStepCategoryStepList($taskItem['step_category_id']), $entityModuleAttributeCustomFieldsMapping[$taskItem['entity_module_id']]);
                            $taskManHour[$taskItem['id']] = $manHour;
                            break;
                        default:
                            $taskManHour[$taskItem['id']] = 0;
                            break;
                    }
                } else {
                    $taskManHour[$taskItem['id']] = $taskItem['man_hour'];
                }
            }
        }

        return $taskManHour;
    }

    /**
     * 计算任务工时
     * @param int $taskId
     * @return bool|int|string|void
     * @throws \Exception
     */
    public function calculateTaskManHour(int $taskId)
    {
        $task = model(TaskModel::class)->field('id,step_type,step_id,step_category_id,entity_id,entity_module_id')->find($taskId);
        if (empty($task)) {
            throw_strack_exception('task not found', ErrorCode::TASK_NOT_FOUND);
        }
        $entity = model(EntityModel::class)->find($task['entity_id']);
        if (empty($entity)) {
            throw_strack_exception('entity not found', ErrorCode::ENTITY_NOT_FOUND);
        }
        $updateData = [
            'id' => $taskId,
        ];
        $stepSkuService = StepSkuService::getInstance();
        $userCertService = UserCertService::getInstance();
        if ($task['step_type'] === 'step') {
            list($manHour,) = $stepSkuService->autoCalculationManHourByEntity($task['entity_id'], $task['entity_module_id'], 'step', $task['step_id']);

        } else if ($task['step_type'] === 'step_category') {
            list($manHour, $stepSkuIds) = $stepSkuService->autoCalculationManHourByEntity($task['entity_id'], $task['entity_module_id'], 'step_category', $task['step_category_id'], $entity['step_workflow_id']);
            if (!empty($stepSkuIds)) {
                $matchCert = $userCertService->matchUserCertBySku($stepSkuIds);
                if (!empty($matchCert)) {
                    $matchCertStr = "{$matchCert['level_category']}-{$matchCert['level']}";
                    $certId = $matchCert['id'];
                    $updateData['level_category'] = $matchCertStr;
                    $updateData['user_cert_id'] = $certId;
                }
            }
        } else {
            return;
        }
        $hourProportion = floatval($entity['hour_proportion']);
        $hourProportion = $hourProportion > 0 ? $hourProportion : 1;
        $updateData['man_hour'] = (float)$manHour * $hourProportion;
        return model(TaskModel::class)->save($updateData);
    }
}
